#include "Expand/PluginsManager.h"
#include "Expand/Plugins/AuthPlugin.h"
#include "Expand/Plugins/GameModePlugin.h"
#include "Expand/Plugins/PlayerPlugin.h"
#include "Expand/Plugins/ItemPlugin.h"
#include "Expand/Plugins/BanPlugin.h"
#include "Expand/Plugins/TpPlugin.h"
#include "Expand/IPlugin.h"

#include <stdexcept>
#include <vector>
#include <filesystem>

#include "Utils/Utils.h"
#include "Network/Client.h"


#ifdef _WIN32

#include "windows.h"

#elif __linux__

#include "dlfcn.h"

#endif


namespace PocketSurvival
{
    PluginsManager::PluginsManager()
    {
        if(std::filesystem::exists("./Plugins") == false)
        {
            if(std::filesystem::create_directories("./Plugins") == false)
            {
                throw std::runtime_error("检测不到插件文件夹，并且无法创建新的插件文件夹");
            }
        }
        if(std::filesystem::exists("./Server") == false)
        {
            if(std::filesystem::create_directories("./Server") == false)
            {
                throw std::runtime_error("检测不到服务文件夹，并且无法创建新的服务文件夹");
            }
        }
    }

    PluginsManager::~PluginsManager() {}

    CmdRunType PluginsManager::processCmdMessage(ClientPtr client, const std::string &message, bool isTermainl)
    {
        if(client == nullptr && isTermainl == false)
        {
            return CmdRunType::Unknow;
        }
        std::vector<std::string> cmdDataVec;
        cmdDataVec.reserve(15);
        Utils::StringSplit(message, " ",cmdDataVec);
        if(cmdDataVec.size() > 15 && client != nullptr)
        {
            return CmdRunType::TooLong;
        }
        auto it = m_cmdMap.find(cmdDataVec[0]);
        if(it != m_cmdMap.end())
        {
            if(isTermainl == true || findPlugin<AuthPlugin>()->getLevelByGuid(client->guid) >= it->second->getUseAuthLevel())
            {
                it->second->process(client, cmdDataVec, isTermainl);
                return CmdRunType::Success;
            }
            return CmdRunType::NoAuth;
        }
        return CmdRunType::NotFound;
    }


    void PluginsManager::load()
    {
        registerPlugin<AuthPlugin>();
        registerPlugin<GameModePlugin>();
        registerPlugin<PlayerPlugin>();
        registerPlugin<ItemPlugin>();
        registerPlugin<BanPlugin>();
        registerPlugin<TpPlugin>();

        std::vector<std::string> cmdVec;
        for(auto &pair : m_pluginMap)
        {
            cmdVec.clear();
            pair.second->getCmds(cmdVec);
            for(const std::string &cmdHead : cmdVec)
            {
                if(m_cmdMap.find(cmdHead) != m_cmdMap.end())
                {
                    throw std::logic_error(fmt::format("插件 {} 的指令 {} 已被其它插件使用，加载失败",pair.second->getPluginName(), cmdHead));
                }
                m_cmdMap[cmdHead] = pair.second;
            }
            pair.second->load();
        }
    }


    void PluginsManager::save()
    {
        for(auto &pair : m_pluginMap)
        {
            pair.second->save();
        }
    }





    
    void PluginsManager::loadLibrary(const std::string &filePath)
    {
        Log::Info(fmt::format("[插件拓展]开始加载 {}", filePath));

#ifdef _WIN32

        HMODULE module = LoadLibrary(filePath.c_str());
        if (module == NULL)
        {
            Log::Warn(fmt::format("[插件拓展]加载 {} 失败", filePath));
            return;
        }
        CorePluginData pluginData;
        pluginData.handler = module;
        pluginData.initializeFunc = (CFunction)GetProcAddress(module, "initialize");
        pluginData.loadFunc = (CFunction)GetProcAddress(module, "load");
        pluginData.saveFunc = (CFunction)GetProcAddress(module, "save");

        Log::Info(fmt::format("[插件拓展]成功加载 {}", filePath));
        m_libraryPtrMap[filePath] = pluginData;

#elif __linux__

        void *module = dlopen(filePath.c_str(), RTLD_LAZY);
        if(module == NULL)
        {
            Log::Warn(fmt::format("[插件拓展]加载 {} 失败", filePath));
            return;
        }
        CorePluginData pluginData;
        pluginData.handler = module;
        pluginData.initializeFunc = (CFunction)dlsym(module, "initialize");
        pluginData.loadFunc = (CFunction)dlsym(module, "load");
        pluginData.saveFunc = (CFunction)dlsym(module, "save");

        Log::Info(fmt::format("[插件拓展]成功加载 {}", filePath));
        m_libraryPtrMap[filePath] = pluginData;

#endif

    }




    void PluginsManager::loadCorePluginsFiles()
    {
        if(std::filesystem::exists("./Plugins") == true)
        {
            std::vector<std::string> vecStr;
            vecStr.reserve(10);

            // 遍历该文件夹下面的所有文件
            for (const auto &pair : std::filesystem::recursive_directory_iterator("./Plugins"))
            {
                if(std::filesystem::is_regular_file(pair))
                {
                    // 切割文件名称，并且需要以.json结尾的文件才会进行加载
                    std::string fileName = pair.path().filename().string();
                    vecStr.clear();
                    Utils::StringSplit(fileName, ".", vecStr);

                    std::string fileEnd;
#ifdef _WIN32

                    fileEnd = "dll";

#elif __linux__

                    fileEnd = "so";

#endif
                    if(vecStr.size() >= 2 && vecStr[vecStr.size() - 1] == fileEnd)
                    {
                        loadLibrary(pair.path().string());
                    }
                }
            }

            for(auto &pair : m_libraryPtrMap)
            {
                pair.second.initializeFunc();
            }

        }

    }

} // namespace PocketSurvival
